package slicegen;

import inset.RawInsetGenerator;

import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
import java.util.List;

import slicegen.Polygon.WindingDirection;

public class PolygonList extends ArrayList<Polygon>
{
	public PolygonList calculateInsetPolygons(double dist)
	{
		PolygonList insets = new PolygonList();

		for (Polygon polygon : this)
		{
			RawInsetGenerator rig = new RawInsetGenerator(polygon);
			rig.generateBisectors();

			insets.add(rig.getInset(dist));

			List<Polygon> subPolys = polygon.getSubPolygons();
			 
			 for (Polygon poly : subPolys)
			 {
				 RawInsetGenerator subRig = new RawInsetGenerator(poly);
				 subRig.generateBisectors();
				 
				 insets.add(subRig.getInset(dist));
			 }
		}

		return insets;
	}

	public Shape calculateBisectors(double dist)
	{
		GeneralPath s = new GeneralPath();

		for (Polygon poly : this)
		{
			RawInsetGenerator rig = new RawInsetGenerator(poly);
			rig.generateBisectors();

			ArrayList<Ray> bisectors = rig.getBisectors();

			for (Ray ray : bisectors)
			{
				ray.setRayLength(0.1);
				s.append(ray.getLine(), false);
			}
			
			List<Polygon> subPolys = poly.getSubPolygons();
			
			for (Polygon spoly : subPolys)
			 {
				 RawInsetGenerator subRig = new RawInsetGenerator(spoly);
				 subRig.generateBisectors();				 
				 
				 ArrayList<Ray> bi = subRig.getBisectors();
				 
				 for (Ray ray : bi)
					{
						ray.setRayLength(0.1);
						s.append(ray.getLine(), false);
					}
			 }
		}

		return s;
	}

	@Override
	public boolean add(Polygon o)
	{
		boolean subPoly = false;

		//See if this polygon is inside another at any point
		for (Polygon poly : this)
		{
			double coords[] = new double[6];

			PathIterator pi = o.getPathIterator(null);

			while (!pi.isDone())
			{
				pi.currentSegment(coords);

				if (poly.contains(coords[0], coords[1]))
				{
					subPoly = true;
					break;
				}

				pi.next();

			}

			if (subPoly)
			{
				o.ensureWindingDirection(WindingDirection.CW);
				poly.addSubPolygon(o);
				break;
			}
		}

		//Is a new top polygon
		if (!subPoly)
		{
			o.ensureWindingDirection(WindingDirection.CCW);
			super.add(o);
		}
		
		return true;
	}

	public ArrayList<ArrayList<Line>> getAllSegments()
	{
		ArrayList<ArrayList<Line>> allLines = new ArrayList<ArrayList<Line>>(size());

		for (Polygon poly : this)
		{
			allLines.add(poly.getLineSegments());

			List<Polygon> subPolys = poly.getSubPolygons();

			for (Polygon polygon : subPolys)
			{
				allLines.add(polygon.getLineSegments());
			}
		}

		return allLines;
	}

	public Shape getShape()
	{
		GeneralPath path = new GeneralPath();

		for (Polygon poly : this)
		{
			path.append(poly, false);

			List<Polygon> subPolys = poly.getSubPolygons();

			for (Polygon polygon : subPolys)
			{
				path.append(polygon, false);
			}
		}

		return path;
	}

	public Rectangle getBounds()
	{
		Area totalArea = new Area();
		
		for (Polygon poly : this)
		{
			totalArea.add(new Area(poly.getBounds2D()));
		}
		
		return totalArea.getBounds();
	}
}
